#include"ExpressionTree.h"

#include<stack>
#include<queue>
#include<sstream>

using namespace std;

expressionTree::expressionTree(const string & postfix) {
	istringstream in(postfix);
	char operators;
	stack<expressionTree*>	trees;

	while (!in.eof()) {
		operators = putExpressionIntoStack(in, trees);
		if (in.eof())
			break;
		compoundNewTree(operators, trees);
	}
	this->setLTree(trees.top()->getLTree());
	this->setRTree(trees.top()->getRTree());
	this->setData(trees.top()->getData());
}

char expressionTree::putExpressionIntoStack(istringstream &in, stack<expressionTree*> &trees) {
	char ch;
	string doublestr;
	while ((in >> ch)) {
		if (isdigit(ch) || ch == '.') {
			while (ch != '#') {
				doublestr.push_back(ch);
				in >> ch;
			}
			expressionTree *ptr = new expressionTree(false, stod(doublestr));
			if (ptr == nullptr) {
				exit(EXIT_FAILURE);
			}
			trees.push(ptr);
			doublestr.clear();
		}
		else if (ch != '#') {
			break;
		}
	}
	return ch;
}

const string expressionTree::modify(string &doublestr) {
	for (auto i = doublestr.size() - 1; i > 0; --i) {
		if (doublestr[i] == '0' || doublestr[i] == '.')
			doublestr.erase(doublestr.begin() + i);
		else {
			break;
		}
	}
	doublestr.push_back(' ');
	return doublestr;
}

void expressionTree::compoundNewTree(char operators, stack<expressionTree*> &trees) {
	expressionTree *ptr = new expressionTree(true, operators);
	ptr->setRTree(trees.top());
	trees.pop();
	ptr->setLTree(trees.top());
	trees.pop();
	trees.push(ptr);
}

expressionTree::expressionTree(bool isOperator, char data, expressionTree* Ltree, expressionTree *Rtree)
	:isOperators(isOperator), operators(data), LTree(Ltree), RTree(Rtree) {
}

expressionTree::expressionTree(bool isOperator, double data, expressionTree* Ltree, expressionTree *Rtree)
	: isOperators(isOperator), operand(data), LTree(Ltree), RTree(Rtree) {
}

void expressionTree::destruct(){
		stack<expressionTree*> Stack;
		queue<expressionTree*> Queue;

		expressionTree *ptr;
		Queue.push(this);
		while (!Queue.empty()) {
			ptr = Queue.front();
			Queue.pop();
			if (ptr->getLTree() != nullptr) {
				Queue.push(ptr->getLTree());
				Queue.push(ptr->getRTree());
				Stack.push(ptr->getLTree());
				Stack.push(ptr->getRTree());
			}
		}
		while (!Stack.empty()) {
			ptr = Stack.top();
			Stack.pop();
			delete ptr;
		}
}

expressionTree::~expressionTree() {
}

bool expressionTree::isOperator() {
	return isOperators;
}

void expressionTree::setDataType(bool isOperators){
	if (isOperators) {
		this->isOperators = true;
	}
	else {
		this->isOperators = false;
	}
}

inline void expressionTree::setData(const string & data) {
	if (isdigit(data[0])) {
		operand = stod(data);
	}
	else {
		operators = data[0];
	}
	setDataType(!isdigit(data[0]));
}

string expressionTree::getData() {
	string temp;
	if (isOperator()) {
		temp.push_back(operators);
	}
	else {
		temp.append(to_string(operand));
	}
	return modify(temp);
}

inline void expressionTree::setLTree(expressionTree * ltree) {
	LTree = ltree;
}

inline void expressionTree::setRTree(expressionTree * rtree) {
	RTree = rtree;
}

inline expressionTree *expressionTree::getLTree() {
	return LTree;
}

inline expressionTree *expressionTree::getRTree() {
	return RTree;
}

bool expressionTree::visit(string &expression) {
	expression.append(getData());
	return true;
}

string expressionTree::getPrefixExpression() {
	stack<expressionTree*> Stack;
	Stack.push(this);
	string expression;
	expressionTree *ptr;
	while (!Stack.empty()) {
		ptr = Stack.top();
		Stack.pop();
		do {
			ptr->visit(expression);
			if (ptr->getRTree() != NULL)
				Stack.push(ptr->getRTree());
			ptr = ptr->getLTree();
		} while (ptr != NULL);
	}
	return expression;
}

bool expressionTree::getInfixExpression(string &infixExpression) {
	if (this != nullptr) {
		if(getLTree()!= nullptr)
			infixExpression.push_back('(');
		if (getLTree()->getInfixExpression(infixExpression))
			if (visit(infixExpression))
				if (getRTree()->getInfixExpression(infixExpression)) {
					if(getRTree()!=nullptr)
						infixExpression.push_back(')');
					return true;
				}
		return false;
	}
	return true;
}

string expressionTree::getPostfixExpression() {
	stack<expressionTree*> Stack1, Stack2;
	Stack1.push(this);
	string postfixExpression;
	expressionTree *ptr;
	while (!Stack1.empty()) {
		ptr = Stack1.top();
		Stack1.pop();
		Stack2.push(ptr);
		do {
			if (ptr->getLTree() != NULL)
				Stack1.push(ptr->getLTree());
			if (ptr->getRTree() != NULL)
				Stack2.push(ptr->getRTree());
			ptr = ptr->getRTree();
		} while (ptr != NULL);
	}
	while (!Stack2.empty()) {
		ptr = Stack2.top();
		Stack2.pop();
		ptr->visit(postfixExpression);
	}
	return postfixExpression;
}